package com.stormragetech.arthas.codec;

import com.stormragetech.arthas.common.annotation.Mapping;
import com.stormragetech.arthas.common.annotation.RequestType;
import com.stormragetech.arthas.common.constant.Constant;
import com.stormragetech.arthas.common.exception.ArthasException;
import com.stormragetech.arthas.dispatcher.DataCache;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.apache.commons.codec.CharEncoding;

import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * description: http request decode handler implement
 *
 * @author: Xue Bin
 * @version: 1.0.0-SNAPSHOT
 */
public class ArthasHttpRequestDecodeHandler implements ArthasHttpRequestDecode {

    private final Method method;

    public ArthasHttpRequestDecodeHandler(Method method) {
        this.method = method;
    }

    @Override
    public ArthasHttpRequest process() throws ArthasException {

        if (RequestType.GET.equals(type(method))) {
            return get();
        } else {
            return post(RequestType.POST);
        }
    }

    private ArthasHttpRequest get() throws ArthasException {

        HttpRequest request = (HttpRequest) DataCache.getData();
        if (null != paramsInUri(request.uri())) {
            Map<String, String> params = paramsInUri(request.uri());
            return new ArthasHttpRequest(RequestType.GET, paramsInUri(request.uri()), null);
        } else {
            return new ArthasHttpRequest();
        }
    }

    private ArthasHttpRequest post(RequestType type) throws ArthasException {

        FullHttpRequest request = (FullHttpRequest) DataCache.getData();
        Map<String, String> getParam = paramsInUri(request.uri());
        Map<String, List<String>> postParam = new QueryStringDecoder(request.content().toString(Charset.forName(CharEncoding.UTF_8)), false).parameters();

        return new ArthasHttpRequest(type, getParam, postParam);
    }

    private RequestType type(Method method) throws ArthasException {

        HttpRequest request = (HttpRequest) DataCache.getData();
        String hm = request.method().name();
        String dm = method.getDeclaredAnnotation(Mapping.class).method().getValue();

        if (null == hm || null == dm || (!dm.equals("") && !dm.equals(hm))) {
            throw new ArthasException(Constant.CODC_ERR_CODE, Constant.CODC_REQ_TYPE, ArthasException.APP_ERR);
        } else if (RequestType.GET.getValue().equals(dm)) {
            return RequestType.GET;
        } else {
            return RequestType.POST;
        }
    }

    private Map<String, String> paramsInUri(String uri) throws ArthasException {
        if (null != uri && uri.length() > 0) {
            String params = uriSplit(uri);
            return null == params ? null : paramSplit(params);
        } else {
            return null;
        }
    }

    private String uriSplit(String uri) throws ArthasException {
        String[] arr = uri.split("\\?");
        if (arr.length != 2) {
            return null;
        } else {
            return arr[1];
        }
    }

    private Map<String, String> paramSplit(String params) {
        Map<String, String> map = new HashMap<>();
        String[] arr = params.split("&");
        Arrays.stream(arr).forEach((param) -> {
            String[] pa = param.split("=");
            if (pa.length == 2) {
                map.put(pa[0], pa[1]);
            }
        });
        return map;
    }

}
